/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package continuity.View;

import continuity.Direction;
import java.awt.*;

/**
 *
 * @author FornetTeam
 */
public class MapView {
    /**
     * A karakterek megjelenítéséért felelős objektumok.
     */
    private CharacterView[] characterView;
    
    /**
     * Megadja, hogy rá vagyunk-e közelítve a karekterre.
     */
    private boolean zoomed;
    
    /**
     * A szobákat tartalmazó táblázat.
     */
    private RoomView[][] rooms;
    
    /**
     * Az üres szoba helye.
     */
    private int[] emptyRoomPosition;
    
    public MapView(RoomView[][] rooms, int emptyRoomPositionX, int emptyRoomPositionY){
        zoomed = false;
        
        this.rooms = rooms;
        
        emptyRoomPosition = new int[2];
        emptyRoomPosition[0] = emptyRoomPositionX;
        emptyRoomPosition[1] = emptyRoomPositionY;
        
        characterView = new CharacterView[2];
        characterView[0] = new CharacterView(ViewParameters.FatCharacter);
        characterView[1] = new CharacterView(ViewParameters.MuscleCharacter);
    }
    
    /**
     * A karakter felugrik egy mezőnyit.
     * @param characterNumber A karakter sorszáma.
     */
    public void jump(int characterNumber) {
        characterView[characterNumber].move(0, -ViewParameters.SpeedY);
    }
        
    /**
     * A karakter zuhan egy mezőt.
     * @param characterNumber A karakter sorszáma.
     */
    public void fall(int characterNumber) {
        characterView[characterNumber].move(0, ViewParameters.SpeedY);
    }

    /**
     * A karaktert mozgató függvény.
     * @param characterNumber A karakter sorszáma.
     * @param dir A mozgás iránya.
     */
    public void move(int characterNumber, Direction dir) {
        if (dir == Direction.Left){
            characterView[characterNumber].move(-ViewParameters.SpeedX , 0);
        } else if (dir == Direction.Right){
            characterView[characterNumber].move(ViewParameters.SpeedX, 0);
        } else {
            throw new IllegalArgumentException("The direction should be left or right.");
        }
    }

    /**
     * Az üres mező elmozdítása megadott irányba.
     * @param dir A mozgatással ellentétes irány.
     */
    public void swap(Direction dir) {
        /**
         * A mozgatás menete:
         * -A két szoba megcserélése.
         * -Az üres szoba helyének frissítése.
         */
        if (dir == Direction.Down){
            RoomView emptyRoomView = rooms[emptyRoomPosition[0]][emptyRoomPosition[1]];
            rooms[emptyRoomPosition[0]][emptyRoomPosition[1]] = rooms[emptyRoomPosition[0]+1][emptyRoomPosition[1]];
            rooms[emptyRoomPosition[0]+1][emptyRoomPosition[1]] = emptyRoomView;
            emptyRoomPosition[0]++;
        } else if (dir == Direction.Up){
            RoomView emptyRoomView = rooms[emptyRoomPosition[0]][emptyRoomPosition[1]];
            rooms[emptyRoomPosition[0]][emptyRoomPosition[1]] = rooms[emptyRoomPosition[0]-1][emptyRoomPosition[1]];
            rooms[emptyRoomPosition[0]-1][emptyRoomPosition[1]] = emptyRoomView;
            emptyRoomPosition[0]--;
        } else if (dir == Direction.Left){
            RoomView emptyRoomView = rooms[emptyRoomPosition[0]][emptyRoomPosition[1]];
            rooms[emptyRoomPosition[0]][emptyRoomPosition[1]] = rooms[emptyRoomPosition[0]][emptyRoomPosition[1]-1];
            rooms[emptyRoomPosition[0]][emptyRoomPosition[1]-1] = emptyRoomView;
            emptyRoomPosition[1]--;
        } else if (dir == Direction.Right){
            RoomView emptyRoomView = rooms[emptyRoomPosition[0]][emptyRoomPosition[1]];
            rooms[emptyRoomPosition[0]][emptyRoomPosition[1]] = rooms[emptyRoomPosition[0]][emptyRoomPosition[1]+1];
            rooms[emptyRoomPosition[0]][emptyRoomPosition[1]+1] = emptyRoomView;
            emptyRoomPosition[1]++;
        }
    }
    
    /**
     * Rá tudunk vele közelíteni a karakterre.
     * @param isZoomed true ha a nagyítva legyen a pálya, false, ha nincs.
     */
    public void setZoom(boolean zoomed) {
        this.zoomed = zoomed;
    }
    
    /**
     * Lekérdezi, hogy rá vagyunk-e közelítve a karakterekre.
     * @return Igaz, ha rá vagyunk.
     */
    public boolean getZoom() {
        return zoomed;
    }

    /**
     * A karakter pozíciójánaak lekérdezése.
     */
    public void refreshCharacterPosition(){
        for (int i = 0; i < characterView.length; i++) {
            int x = 0;
            int y = 0;
            if (!characterView[i].getMoving()){
                /**
                 * Ha nem mozgunk.
                 */
                for (int j = 0; j < rooms.length; j++) {
                    x = 0;
                    for (int k = 0; k < rooms[j].length; k++) {
                        int[] characterPosition = rooms[j][k].getCharacterPosition(i);
                        if (characterPosition[0] != -1 &&
                                characterPosition[1] != -1){
                            characterView[i].setPosition(characterPosition[0]+x, characterPosition[1]+y);
                        }
                        x += rooms[j][k].getDimension().width;
                    }
                    y += rooms[j][0].getDimension().height;
                }
            }
        }
    }
    /**
     * A szobák kirajzolása a megfelelő helyre.
     */
    private void paintRooms(Graphics g){
        for (int i = 0; i < rooms.length; i++) {
            for (int j = 0; j < rooms[i].length; j++) {
                Dimension dimension = rooms[i][j].getDimension();
                Graphics roomG = g.create(
                        dimension.width * j,
                        dimension.height * i,
                        dimension.width,
                        dimension.height);
                rooms[i][j].paintView(roomG);
            }
        }
    }
    
    /**
     * A map kirajzolását végzi.
     * @param g A grafikus felület, amire rajzolunk.
     */
    public void paintView(Graphics g) {
        refreshCharacterPosition();
        
        /**
         * Rajzolás
         */
        if (zoomed){
            Rectangle rectangle = g.getClipBounds();
            
            /**
             * Az elválasztó kék vonal.
             */
            int separatorWidth = 4;
            g.setColor(Color.BLUE);
            g.fillRect(
                    rectangle.width/2 - separatorWidth/2,
                    0,
                    separatorWidth,
                    rectangle.height);
            
            
            /**
             * A felső képernyő graphics objektumának létrehozása.
             */
            Graphics leftScreen = g.create(
                    0,
                    0,
                    rectangle.width/2 - separatorWidth/2,
                    rectangle.height); 
            leftScreen.translate(rectangle.width/4 - characterView[0].getPosition()[0],
                    rectangle.height/2 - characterView[0].getPosition()[1]);
            
            /**
             * Az alsó képernyő graphics objektumának létrehozása.
             */
            Graphics rightScreen = g.create(
                    rectangle.width/2 + separatorWidth/2,
                    0,
                    rectangle.width/2 - separatorWidth/2,
                    rectangle.height);
            rightScreen.translate(rectangle.width/4 - characterView[1].getPosition()[0],
                    rectangle.height/2 - characterView[1].getPosition()[1]);
            
            /**
             * A képernyőfelek kirajzolása.
             */
            paintRooms(leftScreen);
            characterView[1].paintView(leftScreen);
            characterView[0].paintView(leftScreen);
            
            paintRooms(rightScreen);
            characterView[0].paintView(rightScreen);
            characterView[1].paintView(rightScreen);
        } else {
            /**
             * Egy szoba méretei.
             */
            Dimension dim=rooms[0][0].getDimension();
            
            /**
             * Map méretei pixelben.
             */
            int mapsizeX=
                    dim.height*
                    rooms.length;
            int mapsizeY=
                    dim.width*
                    rooms[0].length;
            /**
             * Ennyivel kell eltolni a pálya képét, hogy középen legyen.
             */
            int transX=0;
            int transY=0;
            
            /**
             * Két arány számítás.
             */
            ViewParameters.ScaleX=(double)g.getClipBounds().height/mapsizeX;
            ViewParameters.ScaleY=(double)g.getClipBounds().width/mapsizeY;
            
            /**
             * A kisebb arányt alkalmazzuk. Emellett meghatározuk az eltolás mértékét.
             */
            if(ViewParameters.ScaleX<ViewParameters.ScaleY) {
                ViewParameters.ScaleY=ViewParameters.ScaleX;
                transY=(int) (g.getClipBounds().width - mapsizeY*ViewParameters.ScaleY)/2;
            }
            else
            {
                ViewParameters.ScaleX=ViewParameters.ScaleY;
                transX=(int) (g.getClipBounds().height - mapsizeX*ViewParameters.ScaleX)/2;
            }
            
            /**
             * Eltoljuk a megjelenítést a panel közepére.
             */
            g.translate(transY, transX);
            
            /**
             * A nagyítás beállítása.
             */
            ((Graphics2D)g).scale(ViewParameters.ScaleY, ViewParameters.ScaleX);
                       
            /**
             * A szobák kirajzolása a megfelelő helyre.
             */
            paintRooms(g);
            
            /**
             * A karakterek kirajzolása.
             */
            characterView[0].paintView(g);
            characterView[1].paintView(g);        
        }
    }

    /**
     * Be lehet vele állítani, hogy mozognak-e az egyes karakterek.
     * @param characterNumber A karakter sorszáma.
     * @param b Mozog-e.
     */
    public void setMoving(int characterNumber, boolean b) {
        characterView[characterNumber].setMoving(b);
    }
}
